/****************************************************************************
**
** Copyright (C) 2015 basysKom GmbH, opensource@basyskom.com
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtOpcUa module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#ifndef QOPCUATYPE
#define QOPCUATYPE

#include <QtOpcUa/qopcuaglobal.h>
#include <QtOpcUa/qopcuanodeids.h>

#include <QtCore/qmetatype.h>
#include <QtCore/qpair.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qvariant.h>
#include <QtCore/qvector.h>

QT_BEGIN_NAMESPACE

namespace QOpcUa {
Q_OPCUA_EXPORT Q_NAMESPACE

// see OPC-UA Part 3, 5.2.3 & 8.30
enum class NodeClass {
    Undefined = 0,
    Object = 1,
    Variable = 2,
    Method = 4,
    ObjectType = 8,
    VariableType = 16,
    ReferenceType = 32,
    DataType = 64,
    View = 128,
};
Q_ENUM_NS(NodeClass)
Q_DECLARE_FLAGS(NodeClasses, NodeClass)

enum class NodeAttribute {
    None = 0,
    NodeId = (1 << 0),
    NodeClass = (1 << 1),
    BrowseName = (1 << 2),
    DisplayName = (1 << 3),
    Description = (1 << 4),
    WriteMask = (1 << 5),
    UserWriteMask = (1 << 6), // Base attributes, see part 4, 5.2.1
    IsAbstract = (1 << 7),
    Symmetric = (1 << 8),
    InverseName = (1 << 9),   // Reference attributes, see part 4, 5.3.1
    ContainsNoLoops = (1 << 10),
    EventNotifier = (1 << 11), // View attributes, see part 4, 5.4
    // Objects also add the EventNotifier attribute, see part 4, 5.5.1
    // ObjectType also add the IsAbstract attribute, see part 4, 5.5.2
    Value = (1 << 12),
    DataType = (1 << 13),
    ValueRank = (1 << 14),
    ArrayDimensions = (1 << 15),
    AccessLevel = (1 << 16),
    UserAccessLevel = (1 << 17),
    MinimumSamplingInterval = (1 << 18),
    Historizing = (1 << 19),   // Value attributes, see part 4, 5.6.2
    // VariableType also adds the Value, DataType, ValueRank, ArrayDimensions
    // and isAbstract attributes, see part 4, 5.6.5
    Executable = (1 << 20),
    UserExecutable = (1 << 21), // Method attributes, see part 4, 5.7
};
Q_ENUM_NS(NodeAttribute)
Q_DECLARE_FLAGS(NodeAttributes, NodeAttribute)

// Defined in OPC-UA part 3, Table 8.
enum class WriteMaskBit : quint32 {
    None = 0,
    AccessLevel = (1 << 0),
    ArrayDimensions = (1 << 1),
    BrowseName = (1 << 2),
    ContainsNoLoops = (1 << 3),
    DataType = (1 << 4),
    Description = (1 << 5),
    DisplayName = (1 << 6),
    EventNotifier = (1 << 7),
    Executable = (1 << 8),
    Historizing = (1 << 9),
    InverseName = (1 << 10),
    IsAbstract = (1 << 11),
    MinimumSamplingInterval = (1 << 12),
    NodeClass = (1 << 13),
    NodeId = (1 << 14),
    Symmetric = (1 << 15),
    UserAccessLevel = (1 << 16),
    UserExecutable = (1 << 17),
    UserWriteMask = (1 << 18),
    ValueRank = (1 << 19),
    WriteMask = (1 << 20),
    ValueForVariableType = (1 << 21),
};
Q_ENUM_NS(WriteMaskBit)
Q_DECLARE_FLAGS(WriteMask, WriteMaskBit)

// Defined in OPC-UA part 3, Table 8.
enum class AccessLevelBit : quint8 {
    None = 0,
    CurrentRead = (1 << 0),
    CurrentWrite = (1 << 1),
    HistoryRead = (1 << 2),
    HistoryWrite = (1 << 3),
    SemanticChange = (1 << 4),
    StatusWrite = (1 << 5),
    TimestampWrite = (1 << 6),
};
Q_ENUM_NS(AccessLevelBit)
Q_DECLARE_FLAGS(AccessLevel, AccessLevelBit)

// Defined in OPC-UA part 3, Table 6.
enum class EventNotifierBit : quint8 {
    None = 0,
    SubscribeToEvents = (1 << 0),
    HistoryRead = (1 << 2),
    HistoryWrite = (1 << 3)
};
Q_ENUM_NS(EventNotifierBit)
Q_DECLARE_FLAGS(EventNotifier, EventNotifierBit)

inline uint qHash(const QOpcUa::NodeAttribute& attr)
{
    return ::qHash(static_cast<uint>(attr));
}

// The reference types are nodes in namespace 0, the enum value is their numeric identifier.
// Identifiers are specified in https://opcfoundation.org/UA/schemas/1.03/NodeIds.csv
enum class ReferenceTypeId : quint32 {
    Unspecified = 0,
    References = 31,
    NonHierarchicalReferences = 32,
    HierarchicalReferences = 33,
    HasChild = 34,
    Organizes = 35,
    HasEventSource = 36,
    HasModellingRule = 37,
    HasEncoding = 38,
    HasDescription = 39,
    HasTypeDefinition = 40,
    GeneratesEvent = 41,
    Aggregates = 44,
    HasSubtype = 45,
    HasProperty = 46,
    HasComponent = 47,
    HasNotifier = 48,
    HasOrderedComponent = 49,
    FromState = 51,
    ToState = 52,
    HasCause = 53,
    HasEffect = 54,
    HasHistoricalConfiguration = 56,
    HasSubStateMachine = 117,
    AlwaysGeneratesEvent = 3065,
    HasTrueSubState = 9004,
    HasFalseSubState = 9005,
    HasCondition = 9006
};
Q_ENUM_NS(ReferenceTypeId)

enum Types
{
    Boolean         = 0,
    Int32           = 1,
    UInt32          = 2,
    Double          = 3,
    Float           = 4,
    String          = 5,
    LocalizedText   = 6,
    DateTime        = 7,
    UInt16          = 8,
    Int16           = 9,
    UInt64          = 10,
    Int64           = 11,
    Byte            = 12,
    SByte           = 13,
    ByteString      = 14,
    XmlElement      = 15,
    NodeId          = 16,
    Guid            = 17,
    QualifiedName   = 18,
    StatusCode      = 19,
    ExtensionObject = 20,
    Range           = 21,
    EUInformation   = 22,
    ComplexNumber   = 23,
    DoubleComplexNumber = 24,
    AxisInformation = 25,
    XV              = 26,
    ExpandedNodeId  = 27,
    Argument        = 28,
    Undefined       = 0xFFFFFFFF
};
Q_ENUM_NS(Types)

enum UaStatusCode : quint32
{
    Good = 0,
    BadUnexpectedError = 0x80010000,
    BadInternalError = 0x80020000,
    BadOutOfMemory = 0x80030000,
    BadResourceUnavailable = 0x80040000,
    BadCommunicationError = 0x80050000,
    BadEncodingError = 0x80060000,
    BadDecodingError = 0x80070000,
    BadEncodingLimitsExceeded = 0x80080000,
    BadRequestTooLarge = 0x80B80000,
    BadResponseTooLarge = 0x80B90000,
    BadUnknownResponse = 0x80090000,
    BadTimeout = 0x800A0000,
    BadServiceUnsupported = 0x800B0000,
    BadShutdown = 0x800C0000,
    BadServerNotConnected = 0x800D0000,
    BadServerHalted = 0x800E0000,
    BadNothingToDo = 0x800F0000,
    BadTooManyOperations = 0x80100000,
    BadTooManyMonitoredItems = 0x80DB0000,
    BadDataTypeIdUnknown = 0x80110000,
    BadCertificateInvalid = 0x80120000,
    BadSecurityChecksFailed = 0x80130000,
    BadCertificateTimeInvalid = 0x80140000,
    BadCertificateIssuerTimeInvalid = 0x80150000,
    BadCertificateHostNameInvalid = 0x80160000,
    BadCertificateUriInvalid = 0x80170000,
    BadCertificateUseNotAllowed = 0x80180000,
    BadCertificateIssuerUseNotAllowed = 0x80190000,
    BadCertificateUntrusted = 0x801A0000,
    BadCertificateRevocationUnknown = 0x801B0000,
    BadCertificateIssuerRevocationUnknown = 0x801C0000,
    BadCertificateRevoked = 0x801D0000,
    BadCertificateIssuerRevoked = 0x801E0000,
    BadCertificateChainIncomplete = 0x810D0000,
    BadUserAccessDenied = 0x801F0000,
    BadIdentityTokenInvalid = 0x80200000,
    BadIdentityTokenRejected = 0x80210000,
    BadSecureChannelIdInvalid = 0x80220000,
    BadInvalidTimestamp = 0x80230000,
    BadNonceInvalid = 0x80240000,
    BadSessionIdInvalid = 0x80250000,
    BadSessionClosed = 0x80260000,
    BadSessionNotActivated = 0x80270000,
    BadSubscriptionIdInvalid = 0x80280000,
    BadRequestHeaderInvalid = 0x802A0000,
    BadTimestampsToReturnInvalid = 0x802B0000,
    BadRequestCancelledByClient = 0x802C0000,
    BadTooManyArguments = 0x80E50000,
    GoodSubscriptionTransferred = 0x002D0000,
    GoodCompletesAsynchronously = 0x002E0000,
    GoodOverload = 0x002F0000,
    GoodClamped = 0x00300000,
    BadNoCommunication = 0x80310000,
    BadWaitingForInitialData = 0x80320000,
    BadNodeIdInvalid = 0x80330000,
    BadNodeIdUnknown = 0x80340000,
    BadAttributeIdInvalid = 0x80350000,
    BadIndexRangeInvalid = 0x80360000,
    BadIndexRangeNoData = 0x80370000,
    BadDataEncodingInvalid = 0x80380000,
    BadDataEncodingUnsupported = 0x80390000,
    BadNotReadable = 0x803A0000,
    BadNotWritable = 0x803B0000,
    BadOutOfRange = 0x803C0000,
    BadNotSupported = 0x803D0000,
    BadNotFound = 0x803E0000,
    BadObjectDeleted = 0x803F0000,
    BadNotImplemented = 0x80400000,
    BadMonitoringModeInvalid = 0x80410000,
    BadMonitoredItemIdInvalid = 0x80420000,
    BadMonitoredItemFilterInvalid = 0x80430000,
    BadMonitoredItemFilterUnsupported = 0x80440000,
    BadFilterNotAllowed = 0x80450000,
    BadStructureMissing = 0x80460000,
    BadEventFilterInvalid = 0x80470000,
    BadContentFilterInvalid = 0x80480000,
    BadFilterOperatorInvalid = 0x80C10000,
    BadFilterOperatorUnsupported = 0x80C20000,
    BadFilterOperandCountMismatch = 0x80C30000,
    BadFilterOperandInvalid = 0x80490000,
    BadFilterElementInvalid = 0x80C40000,
    BadFilterLiteralInvalid = 0x80C50000,
    BadContinuationPointInvalid = 0x804A0000,
    BadNoContinuationPoints = 0x804B0000,
    BadReferenceTypeIdInvalid = 0x804C0000,
    BadBrowseDirectionInvalid = 0x804D0000,
    BadNodeNotInView = 0x804E0000,
    BadServerUriInvalid = 0x804F0000,
    BadServerNameMissing = 0x80500000,
    BadDiscoveryUrlMissing = 0x80510000,
    BadSempahoreFileMissing = 0x80520000,
    BadRequestTypeInvalid = 0x80530000,
    BadSecurityModeRejected = 0x80540000,
    BadSecurityPolicyRejected = 0x80550000,
    BadTooManySessions = 0x80560000,
    BadUserSignatureInvalid = 0x80570000,
    BadApplicationSignatureInvalid = 0x80580000,
    BadNoValidCertificates = 0x80590000,
    BadIdentityChangeNotSupported = 0x80C60000,
    BadRequestCancelledByRequest = 0x805A0000,
    BadParentNodeIdInvalid = 0x805B0000,
    BadReferenceNotAllowed = 0x805C0000,
    BadNodeIdRejected = 0x805D0000,
    BadNodeIdExists = 0x805E0000,
    BadNodeClassInvalid = 0x805F0000,
    BadBrowseNameInvalid = 0x80600000,
    BadBrowseNameDuplicated = 0x80610000,
    BadNodeAttributesInvalid = 0x80620000,
    BadTypeDefinitionInvalid = 0x80630000,
    BadSourceNodeIdInvalid = 0x80640000,
    BadTargetNodeIdInvalid = 0x80650000,
    BadDuplicateReferenceNotAllowed = 0x80660000,
    BadInvalidSelfReference = 0x80670000,
    BadReferenceLocalOnly = 0x80680000,
    BadNoDeleteRights = 0x80690000,
    UncertainReferenceNotDeleted = 0x40BC0000,
    BadServerIndexInvalid = 0x806A0000,
    BadViewIdUnknown = 0x806B0000,
    BadViewTimestampInvalid = 0x80C90000,
    BadViewParameterMismatch = 0x80CA0000,
    BadViewVersionInvalid = 0x80CB0000,
    UncertainNotAllNodesAvailable = 0x40C00000,
    GoodResultsMayBeIncomplete = 0x00BA0000,
    BadNotTypeDefinition = 0x80C80000,
    UncertainReferenceOutOfServer = 0x406C0000,
    BadTooManyMatches = 0x806D0000,
    BadQueryTooComplex = 0x806E0000,
    BadNoMatch = 0x806F0000,
    BadMaxAgeInvalid = 0x80700000,
    BadSecurityModeInsufficient = 0x80E60000,
    BadHistoryOperationInvalid = 0x80710000,
    BadHistoryOperationUnsupported = 0x80720000,
    BadInvalidTimestampArgument = 0x80BD0000,
    BadWriteNotSupported = 0x80730000,
    BadTypeMismatch = 0x80740000,
    BadMethodInvalid = 0x80750000,
    BadArgumentsMissing = 0x80760000,
    BadTooManySubscriptions = 0x80770000,
    BadTooManyPublishRequests = 0x80780000,
    BadNoSubscription = 0x80790000,
    BadSequenceNumberUnknown = 0x807A0000,
    BadMessageNotAvailable = 0x807B0000,
    BadInsufficientClientProfile = 0x807C0000,
    BadStateNotActive = 0x80BF0000,
    BadTcpServerTooBusy = 0x807D0000,
    BadTcpMessageTypeInvalid = 0x807E0000,
    BadTcpSecureChannelUnknown = 0x807F0000,
    BadTcpMessageTooLarge = 0x80800000,
    BadTcpNotEnoughResources = 0x80810000,
    BadTcpInternalError = 0x80820000,
    BadTcpEndpointUrlInvalid = 0x80830000,
    BadRequestInterrupted = 0x80840000,
    BadRequestTimeout = 0x80850000,
    BadSecureChannelClosed = 0x80860000,
    BadSecureChannelTokenUnknown = 0x80870000,
    BadSequenceNumberInvalid = 0x80880000,
    BadProtocolVersionUnsupported = 0x80BE0000,
    BadConfigurationError = 0x80890000,
    BadNotConnected = 0x808A0000,
    BadDeviceFailure = 0x808B0000,
    BadSensorFailure = 0x808C0000,
    BadOutOfService = 0x808D0000,
    BadDeadbandFilterInvalid = 0x808E0000,
    UncertainNoCommunicationLastUsableValue = 0x408F0000,
    UncertainLastUsableValue = 0x40900000,
    UncertainSubstituteValue = 0x40910000,
    UncertainInitialValue = 0x40920000,
    UncertainSensorNotAccurate = 0x40930000,
    UncertainEngineeringUnitsExceeded = 0x40940000,
    UncertainSubNormal = 0x40950000,
    GoodLocalOverride = 0x00960000,
    BadRefreshInProgress = 0x80970000,
    BadConditionAlreadyDisabled = 0x80980000,
    BadConditionAlreadyEnabled = 0x80CC0000,
    BadConditionDisabled = 0x80990000,
    BadEventIdUnknown = 0x809A0000,
    BadEventNotAcknowledgeable = 0x80BB0000,
    BadDialogNotActive = 0x80CD0000,
    BadDialogResponseInvalid = 0x80CE0000,
    BadConditionBranchAlreadyAcked = 0x80CF0000,
    BadConditionBranchAlreadyConfirmed = 0x80D00000,
    BadConditionAlreadyShelved = 0x80D10000,
    BadConditionNotShelved = 0x80D20000,
    BadShelvingTimeOutOfRange = 0x80D30000,
    BadNoData = 0x809B0000,
    BadBoundNotFound = 0x80D70000,
    BadBoundNotSupported = 0x80D80000,
    BadDataLost = 0x809D0000,
    BadDataUnavailable = 0x809E0000,
    BadEntryExists = 0x809F0000,
    BadNoEntryExists = 0x80A00000,
    BadTimestampNotSupported = 0x80A10000,
    GoodEntryInserted = 0x00A20000,
    GoodEntryReplaced = 0x00A30000,
    UncertainDataSubNormal = 0x40A40000,
    GoodNoData = 0x00A50000,
    GoodMoreData = 0x00A60000,
    BadAggregateListMismatch = 0x80D40000,
    BadAggregateNotSupported = 0x80D50000,
    BadAggregateInvalidInputs = 0x80D60000,
    BadAggregateConfigurationRejected = 0x80DA0000,
    GoodDataIgnored = 0x00D90000,
    BadRequestNotAllowed = 0x80E40000,
    GoodEdited = 0x00DC0000,
    GoodPostActionFailed = 0x00DD0000,
    UncertainDominantValueChanged = 0x40DE0000,
    GoodDependentValueChanged = 0x00E00000,
    BadDominantValueChanged = 0x80E10000,
    UncertainDependentValueChanged = 0x40E20000,
    BadDependentValueChanged = 0x80E30000,
    GoodCommunicationEvent = 0x00A70000,
    GoodShutdownEvent = 0x00A80000,
    GoodCallAgain = 0x00A90000,
    GoodNonCriticalTimeout = 0x00AA0000,
    BadInvalidArgument = 0x80AB0000,
    BadConnectionRejected = 0x80AC0000,
    BadDisconnect = 0x80AD0000,
    BadConnectionClosed = 0x80AE0000,
    BadInvalidState = 0x80AF0000,
    BadEndOfStream = 0x80B00000,
    BadNoDataAvailable = 0x80B10000,
    BadWaitingForResponse = 0x80B20000,
    BadOperationAbandoned = 0x80B30000,
    BadExpectedStreamToBlock = 0x80B40000,
    BadWouldBlock = 0x80B50000,
    BadSyntaxError = 0x80B60000,
    BadMaxConnectionsReached = 0x80B70000
};
Q_ENUM_NS(UaStatusCode)

enum class ErrorCategory {
    NoError,
    NodeError,
    AttributeError,
    PermissionError,
    ArgumentError,
    TypeError,
    ConnectionError,
    UnspecifiedError
};
Q_ENUM_NS(ErrorCategory)

Q_OPCUA_EXPORT bool isSuccessStatus(QOpcUa::UaStatusCode statusCode);
Q_OPCUA_EXPORT QOpcUa::ErrorCategory errorCategory(QOpcUa::UaStatusCode statusCode);

// NodeId helpers
Q_OPCUA_EXPORT QString nodeIdFromString(quint16 ns, const QString &identifier);
Q_OPCUA_EXPORT QString nodeIdFromByteString(quint16 ns, const QByteArray &identifier);
Q_OPCUA_EXPORT QString nodeIdFromGuid(quint16 ns, const QUuid &identifier);
Q_OPCUA_EXPORT QString nodeIdFromInteger(quint16 ns, quint32 identifier);
Q_OPCUA_EXPORT QString nodeIdFromReferenceType(QOpcUa::ReferenceTypeId referenceType);
Q_OPCUA_EXPORT bool nodeIdStringSplit(const QString &nodeIdString, quint16 *nsIndex,
                                      QString *identifier, char *identifierType);
Q_OPCUA_EXPORT bool nodeIdEquals(const QString &first, const QString &second);
Q_OPCUA_EXPORT QString namespace0Id(QOpcUa::NodeIds::Namespace0 id);
Q_OPCUA_EXPORT QOpcUa::NodeIds::Namespace0 namespace0IdFromNodeId(const QString &nodeId);
Q_OPCUA_EXPORT QString namespace0IdName(QOpcUa::NodeIds::Namespace0 id);

typedef QPair<QVariant, QOpcUa::Types> TypedVariant;

class QQualifiedNameData;
class Q_OPCUA_EXPORT QQualifiedName
{
public:
    QQualifiedName();
    QQualifiedName(const QOpcUa::QQualifiedName &);
    QQualifiedName(quint16 namespaceIndex, const QString &name);
    QQualifiedName &operator=(const QOpcUa::QQualifiedName &);
    bool operator==(const QOpcUa::QQualifiedName &rhs) const;
    operator QVariant() const;
    ~QQualifiedName();

    QString name() const;
    void setName(const QString &name);

    quint16 namespaceIndex() const;
    void setNamespaceIndex(quint16 namespaceIndex);

private:
    QSharedDataPointer<QOpcUa::QQualifiedNameData> data;
};

class QLocalizedTextData;
class Q_OPCUA_EXPORT QLocalizedText
{
    Q_GADGET
    Q_PROPERTY(QString locale READ locale WRITE setLocale)
    Q_PROPERTY(QString text READ text WRITE setText)

public:
    QLocalizedText();
    QLocalizedText(const QOpcUa::QLocalizedText &);
    QLocalizedText(const QString &locale, const QString &text);
    QLocalizedText &operator=(const QOpcUa::QLocalizedText &);
    bool operator==(const QOpcUa::QLocalizedText &rhs) const;
    operator QVariant() const;
    ~QLocalizedText();

    QString locale() const;
    void setLocale(const QString &locale);

    QString text() const;
    void setText(const QString &text);

private:
    QSharedDataPointer<QOpcUa::QLocalizedTextData> data;
};

class QRangeData;
class Q_OPCUA_EXPORT QRange
{
public:
    QRange();
    QRange(const QOpcUa::QRange &);
    QRange(double low, double high);
    QRange &operator=(const QOpcUa::QRange &);
    bool operator==(const QOpcUa::QRange &rhs) const;
    operator QVariant() const;
    ~QRange();

    double low() const;
    void setLow(double low);

    double high() const;
    void setHigh(double high);

private:
    QSharedDataPointer<QOpcUa::QRangeData> data;
};

class QEUInformationData;
class Q_OPCUA_EXPORT QEUInformation
{
public:
    QEUInformation();
    QEUInformation(const QOpcUa::QEUInformation &);
    QEUInformation(const QString &namespaceUri, qint32 unitId,
                   const QOpcUa::QLocalizedText &displayName, const QOpcUa::QLocalizedText &description);
    QEUInformation &operator=(const QOpcUa::QEUInformation &);
    bool operator==(const QOpcUa::QEUInformation &rhs) const;
    operator QVariant() const;
    ~QEUInformation();

    QString namespaceUri() const;
    void setNamespaceUri(const QString &namespaceUri);

    qint32 unitId() const;
    void setUnitId(qint32 unitId);

    QOpcUa::QLocalizedText displayName() const;
    void setDisplayName(const QOpcUa::QLocalizedText &displayName);

    QOpcUa::QLocalizedText description() const;
    void setDescription(const QOpcUa::QLocalizedText &description);

private:
    QSharedDataPointer<QOpcUa::QEUInformationData> data;
};

class QComplexNumberData;
class Q_OPCUA_EXPORT QComplexNumber
{
public:
    QComplexNumber();
    QComplexNumber(const QOpcUa::QComplexNumber &);
    QComplexNumber(float real, float imaginary);
    QComplexNumber &operator=(const QOpcUa::QComplexNumber &);
    bool operator==(const QOpcUa::QComplexNumber &rhs) const;
    operator QVariant() const;
    ~QComplexNumber();

    float real() const;
    void setReal(float real);

    float imaginary() const;
    void setImaginary(float imaginary);

private:
    QSharedDataPointer<QOpcUa::QComplexNumberData> data;
};

class QDoubleComplexNumberData;
class Q_OPCUA_EXPORT QDoubleComplexNumber
{
public:
    QDoubleComplexNumber();
    QDoubleComplexNumber(const QOpcUa::QDoubleComplexNumber &);
    QDoubleComplexNumber(double real, double imaginary);
    QDoubleComplexNumber &operator=(const QOpcUa::QDoubleComplexNumber &);
    bool operator==(const QOpcUa::QDoubleComplexNumber &rhs) const;
    operator QVariant() const;
    ~QDoubleComplexNumber();

    double real() const;
    void setReal(double real);

    double imaginary() const;
    void setImaginary(double imaginary);

private:
    QSharedDataPointer<QOpcUa::QDoubleComplexNumberData> data;
};

enum class AxisScale : quint32 {
    Linear = 0,
    Log = 1,
    Ln = 2
};

class QAxisInformationData;
class Q_OPCUA_EXPORT QAxisInformation
{
public:
    QAxisInformation();
    QAxisInformation(const QOpcUa::QAxisInformation &);
    QAxisInformation(const QOpcUa::QEUInformation &engineeringUnits, const QOpcUa::QRange &eURange, const QOpcUa::QLocalizedText &title,
                     const QOpcUa::AxisScale &axisScaleType, const QVector<double> &axisSteps);
    QAxisInformation &operator=(const QOpcUa::QAxisInformation &);
    bool operator==(const QOpcUa::QAxisInformation &rhs) const;
    operator QVariant() const;
    ~QAxisInformation();

    QOpcUa::QEUInformation engineeringUnits() const;
    void setEngineeringUnits(const QOpcUa::QEUInformation &engineeringUnits);

    QOpcUa::QRange eURange() const;
    void setEURange(const QOpcUa::QRange &eURange);

    QOpcUa::QLocalizedText title() const;
    void setTitle(const QOpcUa::QLocalizedText &title);

    QOpcUa::AxisScale axisScaleType() const;
    void setAxisScaleType(QOpcUa::AxisScale axisScaleType);

    QVector<double> axisSteps() const;
    void setAxisSteps(const QVector<double> &axisSteps);
    QVector<double> &axisStepsRef();

private:
    QSharedDataPointer<QOpcUa::QAxisInformationData> data;
};

class QXValueData;
class Q_OPCUA_EXPORT QXValue
{
public:
    QXValue();
    QXValue(const QOpcUa::QXValue &);
    QXValue(double x, float value);
    QXValue &operator=(const QOpcUa::QXValue &);
    bool operator==(const QOpcUa::QXValue &rhs) const;
    operator QVariant() const;
    ~QXValue();

    double x() const;
    void setX(double x);

    float value() const;
    void setValue(float value);

private:
    QSharedDataPointer<QOpcUa::QXValueData> data;
};

class QExpandedNodeIdData;
class Q_OPCUA_EXPORT QExpandedNodeId
{
public:
    QExpandedNodeId();
    QExpandedNodeId(const QOpcUa::QExpandedNodeId &);
    QExpandedNodeId(const QString &nodeId);
    QExpandedNodeId(const QString &namespaceUri, const QString &nodeId, quint32 serverIndex = 0);
    QExpandedNodeId &operator=(const QOpcUa::QExpandedNodeId &);
    bool operator==(const QOpcUa::QExpandedNodeId &) const;
    operator QVariant() const;
    ~QExpandedNodeId();

    quint32 serverIndex() const;
    void setServerIndex(quint32 serverIndex);

    QString namespaceUri() const;
    void setNamespaceUri(const QString &namespaceUri);

    QString nodeId() const;
    void setNodeId(const QString &nodeId);

private:
    QSharedDataPointer<QOpcUa::QExpandedNodeIdData> data;
};

class QRelativePathElementData;
class Q_OPCUA_EXPORT QRelativePathElement
{
public:
    QRelativePathElement();
    QRelativePathElement(const QOpcUa::QQualifiedName &target, const QString &refType);
    QRelativePathElement(const QOpcUa::QQualifiedName &target, QOpcUa::ReferenceTypeId refType);
    QRelativePathElement(const QOpcUa::QRelativePathElement &);
    QRelativePathElement &operator=(const QOpcUa::QRelativePathElement &);
    bool operator==(const QOpcUa::QRelativePathElement &rhs) const;
    ~QRelativePathElement();

    QString referenceTypeId() const;
    void setReferenceTypeId(const QString &referenceTypeId);
    void setReferenceTypeId(QOpcUa::ReferenceTypeId referenceTypeId);

    bool isInverse() const;
    void setIsInverse(bool isInverse);

    bool includeSubtypes() const;
    void setIncludeSubtypes(bool includeSubtypes);

    QOpcUa::QQualifiedName targetName() const;
    void setTargetName(const QOpcUa::QQualifiedName &targetName);

private:
    QSharedDataPointer<QOpcUa::QRelativePathElementData> data;
};

class QBrowsePathTargetData;
class Q_OPCUA_EXPORT QBrowsePathTarget
{
public:
    QBrowsePathTarget();
    QBrowsePathTarget(const QOpcUa::QBrowsePathTarget &);
    QBrowsePathTarget &operator=(const QOpcUa::QBrowsePathTarget &);
    bool operator==(const QOpcUa::QBrowsePathTarget &rhs) const;
    ~QBrowsePathTarget();

    QOpcUa::QExpandedNodeId targetId() const;
    QOpcUa::QExpandedNodeId &targetIdRef();
    void setTargetId(const QOpcUa::QExpandedNodeId &targetId);

    quint32 remainingPathIndex() const;
    void setRemainingPathIndex(quint32 remainingPathIndex);

    bool isFullyResolved() const;


private:
    QSharedDataPointer<QOpcUa::QBrowsePathTargetData> data;
};

// OPC-UA part 4, 7.4.4.2
class QElementOperandData;
class Q_OPCUA_EXPORT QElementOperand
{
public:
    QElementOperand();
    QElementOperand(const QElementOperand &);
    QElementOperand(quint32 index);
    QElementOperand &operator=(const QElementOperand &);
    operator QVariant() const;
    ~QElementOperand();

    quint32 index() const;
    void setIndex(quint32 index);

private:
    QSharedDataPointer<QOpcUa::QElementOperandData> data;
};

// OPC-UA part 4, 7.4.4.3
class QLiteralOperandData;
class Q_OPCUA_EXPORT QLiteralOperand
{
public:
    QLiteralOperand();
    QLiteralOperand(const QOpcUa::QLiteralOperand &);
    QLiteralOperand(const QVariant &value, QOpcUa::Types type = QOpcUa::Types::Undefined);
    QLiteralOperand &operator=(const QOpcUa::QLiteralOperand &);
    operator QVariant() const;
    ~QLiteralOperand();

    QVariant value() const;
    void setValue(const QVariant &value);

    QOpcUa::Types type() const;
    void setType(QOpcUa::Types type);

private:
    QSharedDataPointer<QOpcUa::QLiteralOperandData> data;
};

// OPC-UA part 4, 7.4.4.5
class QSimpleAttributeOperandData;
class Q_OPCUA_EXPORT QSimpleAttributeOperand
{
public:
    QSimpleAttributeOperand();
    QSimpleAttributeOperand(const QOpcUa::QSimpleAttributeOperand &);
    QSimpleAttributeOperand(const QString &name, quint16 namespaceIndex = 0,
                            const QString &typeId = QStringLiteral("ns=0;i=2041"), // BaseEventType
                            QOpcUa::NodeAttribute attributeId = QOpcUa::NodeAttribute::Value);
    QSimpleAttributeOperand(QOpcUa::NodeAttribute attributeId,
                            const QString &typeId = QStringLiteral("ns=0;i=2041")); // BaseEventType
    QSimpleAttributeOperand &operator=(const QOpcUa::QSimpleAttributeOperand &);
    bool operator==(const QSimpleAttributeOperand &rhs) const;
    operator QVariant() const;
    ~QSimpleAttributeOperand();

    QString typeId() const;
    void setTypeId(const QString &typeId);

    QVector<QOpcUa::QQualifiedName> browsePath() const;
    QVector<QOpcUa::QQualifiedName> &browsePathRef();
    void setBrowsePath(const QVector<QOpcUa::QQualifiedName> &browsePath);

    QOpcUa::NodeAttribute attributeId() const;
    void setAttributeId(QOpcUa::NodeAttribute attributeId);

    QString indexRange() const;
    void setIndexRange(const QString &indexRange);

private:
    QSharedDataPointer<QOpcUa::QSimpleAttributeOperandData> data;
};

// OPC-UA part 4, 7.4.4.4
class QAttributeOperandData;
class Q_OPCUA_EXPORT QAttributeOperand
{
public:
    QAttributeOperand();
    QAttributeOperand(const QOpcUa::QAttributeOperand &);
    QAttributeOperand &operator=(const QOpcUa::QAttributeOperand &);
    operator QVariant() const;
    ~QAttributeOperand();

    QString nodeId() const;
    void setNodeId(const QString &nodeId);

    QString alias() const;
    void setAlias(const QString &alias);

    QVector<QOpcUa::QRelativePathElement> browsePath() const;
    QVector<QOpcUa::QRelativePathElement> &browsePathRef();
    void setBrowsePath(const QVector<QOpcUa::QRelativePathElement> &browsePath);

    QOpcUa::NodeAttribute attributeId() const;
    void setAttributeId(QOpcUa::NodeAttribute attributeId);

    QString indexRange() const;
    void setIndexRange(const QString &indexRange);

private:
    QSharedDataPointer<QOpcUa::QAttributeOperandData> data;
};

class QContentFilterElementData;
class Q_OPCUA_EXPORT QContentFilterElement
{
public:
    QContentFilterElement();
    QContentFilterElement(const QContentFilterElement &);
    QContentFilterElement &operator=(const QContentFilterElement &);
    bool operator==(const QContentFilterElement &rhs) const;
    operator QVariant() const;
    ~QContentFilterElement();

    // Specified in OPC-UA part 4, Tables 115 and 116
    enum FilterOperator : quint32 {
        Equals = 0,
        IsNull = 1,
        GreaterThan = 2,
        LessThan = 3,
        GreaterThanOrEqual = 4,
        LessThanOrEqual = 5,
        Like = 6,
        Not = 7,
        Between = 8,
        InList = 9,
        And = 10,
        Or = 11,
        Cast = 12,
        InView = 13,
        OfType = 14,
        RelatedTo = 15,
        BitwiseAnd = 16,
        BitwiseOr = 17
    };

    QContentFilterElement &operator<<(FilterOperator op);
    QContentFilterElement &operator<<(const QSimpleAttributeOperand &op);
    QContentFilterElement &operator<<(const QAttributeOperand &op);
    QContentFilterElement &operator<<(const QLiteralOperand &op);
    QContentFilterElement &operator<<(const QElementOperand &op);


    QOpcUa::QContentFilterElement::FilterOperator filterOperator() const;
    void setFilterOperator(QOpcUa::QContentFilterElement::FilterOperator filterOperator);

    QVector<QVariant> filterOperands() const;
    QVector<QVariant> &filterOperandsRef();
    void setFilterOperands(const QVector<QVariant> &filterOperands);

private:
    QSharedDataPointer<QOpcUa::QContentFilterElementData> data;
};

class QContentFilterElementResultData;
class Q_OPCUA_EXPORT QContentFilterElementResult
{
public:
    QContentFilterElementResult();
    QContentFilterElementResult(const QOpcUa::QContentFilterElementResult &);
    QContentFilterElementResult &operator=(const QOpcUa::QContentFilterElementResult &);
    ~QContentFilterElementResult();

    QOpcUa::UaStatusCode statusCode() const;
    void setStatusCode(QOpcUa::UaStatusCode statusCode);

    QVector<QOpcUa::UaStatusCode> operandStatusCodes() const;
    QVector<QOpcUa::UaStatusCode> &operandStatusCodesRef();
    void setOperandStatusCodes(const QVector<QOpcUa::UaStatusCode> &operandStatusCodes);

private:
    QSharedDataPointer<QOpcUa::QContentFilterElementResultData> data;
};

class QEventFilterResultData;
class Q_OPCUA_EXPORT QEventFilterResult
{
public:
    QEventFilterResult();
    QEventFilterResult(const QOpcUa::QEventFilterResult &);
    QEventFilterResult &operator=(const QOpcUa::QEventFilterResult &);
    ~QEventFilterResult();

    bool isGood() const;

    QVector<QOpcUa::UaStatusCode> selectClauseResults() const;
    QVector<QOpcUa::UaStatusCode> &selectClauseResultsRef();
    void setSelectClauseResults(const QVector<QOpcUa::UaStatusCode> &selectClausesResult);

    QVector<QOpcUa::QContentFilterElementResult> whereClauseResults() const;
    QVector<QOpcUa::QContentFilterElementResult> &whereClauseResultsRef();
    void setWhereClauseResults(const QVector<QOpcUa::QContentFilterElementResult> &whereClauseResult);

private:
    QSharedDataPointer<QEventFilterResultData> data;
};

class QUserTokenPolicyData;
class Q_OPCUA_EXPORT QUserTokenPolicy
{
public:
    QUserTokenPolicy();
    QUserTokenPolicy(const QUserTokenPolicy &);
    QUserTokenPolicy &operator=(const QUserTokenPolicy &);
    ~QUserTokenPolicy();

    enum TokenType {
        Anonymous = 0,
        Username = 1,
        Certificate = 2,
        IssuedToken = 3
    };

    QString policyId() const;
    void setPolicyId(const QString &policyId);

    TokenType tokenType() const;
    void setTokenType(QOpcUa::QUserTokenPolicy::TokenType tokenType);

    QString issuedTokenType() const;
    void setIssuedTokenType(const QString &issuedTokenType);

    QString issuerEndpointUrl() const;
    void setIssuerEndpointUrl(const QString &issuerEndpointUrl);

    QString securityPolicyUri() const;
    void setSecurityPolicyUri(const QString &securityPolicyUri);

private:
    QSharedDataPointer<QUserTokenPolicyData> data;
};

class QApplicationDescriptionData;
class Q_OPCUA_EXPORT QApplicationDescription
{
public:
    QApplicationDescription();
    QApplicationDescription(const QApplicationDescription &);
    QApplicationDescription &operator=(const QApplicationDescription &);
    ~QApplicationDescription();

    enum ApplicationType {
        Server = 0,
        Client = 1,
        ClientAndServer = 2,
        DiscoveryServer = 3
    };

    QString applicationUri() const;
    void setApplicationUri(const QString &applicationUri);

    QString productUri() const;
    void setProductUri(const QString &productUri);

    QOpcUa::QLocalizedText applicationName() const;
    void setApplicationName(const QOpcUa::QLocalizedText &applicationName);

    QOpcUa::QApplicationDescription::ApplicationType applicationType() const;
    void setApplicationType(QOpcUa::QApplicationDescription::ApplicationType applicationType);

    QString gatewayServerUri() const;
    void setGatewayServerUri(const QString &gatewayServerUri);

    QString discoveryProfileUri() const;
    void setDiscoveryProfileUri(const QString &discoveryProfileUri);

    QVector<QString> discoveryUrls() const;
    QVector<QString> &discoveryUrlsRef();
    void setDiscoveryUrls(const QVector<QString> &discoveryUrls);

private:
    QSharedDataPointer<QApplicationDescriptionData> data;
};

class QEndpointDescriptionData;
class Q_OPCUA_EXPORT QEndpointDescription
{
public:
    QEndpointDescription();
    QEndpointDescription(const QEndpointDescription &);
    QEndpointDescription &operator=(const QEndpointDescription &);
    ~QEndpointDescription();

    enum MessageSecurityMode {
        Invalid = 0,
        None = 1,
        Sign = 2,
        SignAndEncrypt = 3
    };

    QString endpointUrl() const;
    void setEndpointUrl(const QString &endpointUrl);

    QOpcUa::QApplicationDescription server() const;
    QOpcUa::QApplicationDescription &serverRef();
    void setServer(const QOpcUa::QApplicationDescription &server);

    QByteArray serverCertificate() const;
    void setServerCertificate(const QByteArray &serverCertificate);

    QOpcUa::QEndpointDescription::MessageSecurityMode securityMode() const;
    void setSecurityMode(QOpcUa::QEndpointDescription::MessageSecurityMode securityMode);

    QString securityPolicyUri() const;
    void setSecurityPolicyUri(const QString &securityPolicyUri);

    QVector<QOpcUa::QUserTokenPolicy> userIdentityTokens() const;
    QVector<QOpcUa::QUserTokenPolicy> &userIdentityTokensRef();
    void setUserIdentityTokens(const QVector<QOpcUa::QUserTokenPolicy> &userIdentityTokens);

    QString transportProfileUri() const;
    void setTransportProfileUri(const QString &transportProfileUri);

    quint8 securityLevel() const;
    void setSecurityLevel(quint8 securityLevel);

private:
    QSharedDataPointer<QEndpointDescriptionData> data;
};

class QArgumentData;
class Q_OPCUA_EXPORT QArgument
{
public:
    QArgument();
    QArgument(const QArgument &rhs);
    QArgument(const QString &name, const QString &dataTypeId, qint32 valueRank,
              const QVector<quint32> &arrayDimensions, const QOpcUa::QLocalizedText &description);
    QArgument &operator=(const QArgument &);
    bool operator==(const QArgument &other) const;
    operator QVariant() const;
    ~QArgument();

    QString name() const;
    void setName(const QString &name);

    QString dataTypeId() const;
    void setDataTypeId(const QString &dataTypeId);

    qint32 valueRank() const;
    void setValueRank(qint32 valueRank);

    QVector<quint32> arrayDimensions() const;
    QVector<quint32> &arrayDimensionsRef();
    void setArrayDimensions(const QVector<quint32> &arrayDimensions);

    QOpcUa::QLocalizedText description() const;
    void setDescription(const QOpcUa::QLocalizedText &description);

private:
    QSharedDataPointer<QOpcUa::QArgumentData> data;
};

class QExtensionObjectData;
class Q_OPCUA_EXPORT QExtensionObject
{
public:
    enum Encoding {
        NoBody = 0,
        ByteString = 1,
        Xml = 2
    };

    QExtensionObject();
    QExtensionObject(const QOpcUa::QExtensionObject &);
    ~QExtensionObject();
    QExtensionObject &operator=(const QOpcUa::QExtensionObject &);
    bool operator==(const QOpcUa::QExtensionObject &rhs) const;
    operator QVariant() const;

    QString encodingTypeId() const;
    void setEncodingTypeId(const QString &encodingTypeId);

    QByteArray encodedBody() const;
    QByteArray &encodedBodyRef();
    void setEncodedBody(const QByteArray &encodedBody);

    QOpcUa::QExtensionObject::Encoding encoding() const;
    void setEncoding(QOpcUa::QExtensionObject::Encoding encoding);

private:
    QSharedDataPointer<QOpcUa::QExtensionObjectData> data;
};

class QMultiDimensionalArrayData;
class Q_OPCUA_EXPORT QMultiDimensionalArray
{
public:
    QMultiDimensionalArray();
    QMultiDimensionalArray(const QOpcUa::QMultiDimensionalArray &other);
    QMultiDimensionalArray &operator=(const QOpcUa::QMultiDimensionalArray &rhs);
    QMultiDimensionalArray(const QVariantList &valueArray, const QVector<quint32> &arrayDimensions);
    QMultiDimensionalArray(const QVector<quint32> &arrayDimensions);
    ~QMultiDimensionalArray();

    QVariantList valueArray() const;
    QVariantList &valueArrayRef();
    void setValueArray(const QVariantList &valueArray);

    int arrayIndex(const QVector<quint32> &indices) const;
    QVariant value(const QVector<quint32> &indices) const;
    bool setValue(const QVector<quint32> &indices, const QVariant &value);

    bool isValid() const;

    QVector<quint32> arrayDimensions() const;
    void setArrayDimensions(const QVector<quint32> &arrayDimensions);

    bool operator==(const QOpcUa::QMultiDimensionalArray &other) const;

    operator QVariant() const;

private:
    QSharedDataPointer<QOpcUa::QMultiDimensionalArrayData> data;
};

}

Q_DECLARE_TYPEINFO(QOpcUa::Types, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QOpcUa::UaStatusCode, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QOpcUa::ErrorCategory, Q_PRIMITIVE_TYPE);

Q_DECLARE_TYPEINFO(QOpcUa::NodeClass, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QOpcUa::NodeAttribute, Q_PRIMITIVE_TYPE);
Q_DECLARE_OPERATORS_FOR_FLAGS(QOpcUa::NodeAttributes)
Q_DECLARE_OPERATORS_FOR_FLAGS(QOpcUa::WriteMask)
Q_DECLARE_OPERATORS_FOR_FLAGS(QOpcUa::AccessLevel)
Q_DECLARE_OPERATORS_FOR_FLAGS(QOpcUa::EventNotifier)
Q_DECLARE_OPERATORS_FOR_FLAGS(QOpcUa::NodeClasses)
Q_DECLARE_TYPEINFO(QOpcUa::ReferenceTypeId, Q_PRIMITIVE_TYPE);

QT_END_NAMESPACE

Q_DECLARE_METATYPE(QOpcUa::Types)
Q_DECLARE_METATYPE(QOpcUa::TypedVariant)
Q_DECLARE_METATYPE(QOpcUa::QQualifiedName)
Q_DECLARE_METATYPE(QOpcUa::QLocalizedText)
Q_DECLARE_METATYPE(QOpcUa::UaStatusCode)
Q_DECLARE_METATYPE(QOpcUa::ErrorCategory)
Q_DECLARE_METATYPE(QOpcUa::NodeClass)
Q_DECLARE_METATYPE(QOpcUa::NodeAttribute)
Q_DECLARE_METATYPE(QOpcUa::NodeAttributes)
Q_DECLARE_METATYPE(QOpcUa::WriteMaskBit)
Q_DECLARE_METATYPE(QOpcUa::WriteMask)
Q_DECLARE_METATYPE(QOpcUa::AccessLevelBit)
Q_DECLARE_METATYPE(QOpcUa::AccessLevel)
Q_DECLARE_METATYPE(QOpcUa::EventNotifierBit)
Q_DECLARE_METATYPE(QOpcUa::EventNotifier)
Q_DECLARE_METATYPE(QOpcUa::ReferenceTypeId)
Q_DECLARE_METATYPE(QOpcUa::NodeClasses)
Q_DECLARE_METATYPE(QOpcUa::QRange)
Q_DECLARE_METATYPE(QOpcUa::QEUInformation)
Q_DECLARE_METATYPE(QOpcUa::QComplexNumber)
Q_DECLARE_METATYPE(QOpcUa::QDoubleComplexNumber)
Q_DECLARE_METATYPE(QOpcUa::QAxisInformation)
Q_DECLARE_METATYPE(QOpcUa::QXValue)
Q_DECLARE_METATYPE(QOpcUa::QExpandedNodeId)
Q_DECLARE_METATYPE(QOpcUa::QRelativePathElement)
Q_DECLARE_METATYPE(QOpcUa::QBrowsePathTarget)
Q_DECLARE_METATYPE(QOpcUa::QContentFilterElement)
Q_DECLARE_METATYPE(QOpcUa::QElementOperand)
Q_DECLARE_METATYPE(QOpcUa::QLiteralOperand)
Q_DECLARE_METATYPE(QOpcUa::QSimpleAttributeOperand)
Q_DECLARE_METATYPE(QOpcUa::QAttributeOperand)
Q_DECLARE_METATYPE(QOpcUa::QContentFilterElementResult)
Q_DECLARE_METATYPE(QOpcUa::QEventFilterResult)
Q_DECLARE_METATYPE(QOpcUa::QUserTokenPolicy)
Q_DECLARE_METATYPE(QOpcUa::QApplicationDescription)
Q_DECLARE_METATYPE(QOpcUa::QEndpointDescription)
Q_DECLARE_METATYPE(QOpcUa::QArgument)
Q_DECLARE_METATYPE(QOpcUa::QExtensionObject)
Q_DECLARE_METATYPE(QOpcUa::QMultiDimensionalArray)

#endif // QOPCUATYPE
